package org.example.gxpt.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.example.gxpt.common.constant.*;
import org.example.gxpt.common.context.LoginContext;
import org.example.gxpt.common.context.SecurityContext;
import org.example.gxpt.common.properties.JwtProperties;
import org.example.gxpt.common.properties.RedisProperties;
import org.example.gxpt.common.result.PageResult;
import org.example.gxpt.common.result.Result;
import org.example.gxpt.common.utils.JwtUtil;
import org.example.gxpt.mapper.ShowroomAdminMapper;
import org.example.gxpt.mapper.ShowroomMapper;
import org.example.gxpt.mapper.UserRoleMapper;
import org.example.gxpt.pojo.dto.LoginDTO;
import org.example.gxpt.pojo.dto.ShowroomAdminDTO;
import org.example.gxpt.pojo.dto.ShowroomAdminPageQueryDTO;
import org.example.gxpt.pojo.dto.ShowroomAdminUpdateDTO;
import org.example.gxpt.pojo.entity.Showroom;
import org.example.gxpt.pojo.entity.ShowroomAdmin;
import org.example.gxpt.pojo.entity.UserRole;
import org.example.gxpt.pojo.userdetails.LoginUser;
import org.example.gxpt.pojo.vo.ShowroomAdminLoginVO;
import org.example.gxpt.pojo.vo.ShowroomAdminQueryVO;
import org.example.gxpt.service.ShowroomAdminService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
public class ShowroomAdminServiceImpl implements ShowroomAdminService {

    @Autowired
    private ShowroomAdminMapper showroomAdminMapper;

    @Autowired
    private ShowroomMapper showroomMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedisProperties redisProperties;

    @Autowired
    private UserRoleMapper userRoleMapper;

    /**
     * 展厅管理员注册
     *
     * @param showroomAdminDTO
     */
    @Override
    @Transactional
    public void save(ShowroomAdminDTO showroomAdminDTO) {

        ShowroomAdmin showroomAdmin = new ShowroomAdmin();
        BeanUtils.copyProperties(showroomAdminDTO, showroomAdmin);

        Showroom showroom = showroomMapper.getShowroomById(showroomAdmin.getShowroomId());
        if (Objects.isNull(showroom)) throw new RuntimeException("展厅不存在");

//        showroomAdmin.setPassword(DigestUtils.md5DigestAsHex(showroomAdmin.getPassword().getBytes()));
        showroomAdmin.setPassword(passwordEncoder.encode(showroomAdminDTO.getPassword()));
        showroomAdminMapper.insert(showroomAdmin);
        UserRole userRole = new UserRole();
        userRole.setUsername(showroomAdmin.getUsername());
        userRole.setPhone(showroomAdmin.getPhone());
        userRole.setRole(RoleConstant.SHOWROOM_ADMIN);
        userRole.setRoleId(showroomAdmin.getId());
        userRoleMapper.insert(userRole);
    }

    /**
     * 展厅管理员登陆
     *
     * @param loginDTO
     * @return
     */
    @Override
    public ShowroomAdminLoginVO login(LoginDTO loginDTO) {

        //存储当前登录用户的角色信息，在UserDetailsServiceImpl中取出用于判断当前登录用户的角色，从对应的mapper中查询
        LoginContext.setCurrentRole(LoginRoleConstant.SHOWROOM_ADMIN);

        //AuthenticationManager authenticate进行认证
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginDTO.getUsername(), loginDTO.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);

        //如果认证没通过，给出对应提示
        if(Objects.isNull(authenticate)){
            throw new RuntimeException("登录失败");
        }

        //如果认证通过，使用生成一个jwt，存入loginVO中返回
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        ShowroomAdmin showroomAdmin = loginUser.getShowroomAdmin();

        //生成jwt令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.ROLE, RoleConstant.SHOWROOM_ADMIN);
        claims.put(JwtClaimsConstant.ID, showroomAdmin.getId());
        String token = JwtUtil.createJWT(
                jwtProperties.getSecretKey(),
                jwtProperties.getTtl(),
                claims);

        Showroom showroom = showroomMapper.getShowroomById(showroomAdmin.getShowroomId());
        if (Objects.isNull(showroom)) throw new RuntimeException("展厅不存在");

        ShowroomAdminLoginVO showroomAdminLoginVO = ShowroomAdminLoginVO.builder()
                .id(showroomAdmin.getId())
                .name(showroomAdmin.getName())
                .username(showroomAdmin.getUsername())
                .token(token)
                .avatar(showroomAdmin.getAvatar())
                .showroomId(showroomAdmin.getShowroomId())
                .showroomName(showroom.getName())
                .build();

        //把完整的用户信息存入redis
        redisTemplate.opsForValue().set(RedisConstant.LOGIN_SHOWROOM_ADMIN + showroomAdmin.getId().toString(), loginUser, redisProperties.getTtl(), TimeUnit.MILLISECONDS);

        return showroomAdminLoginVO;
    }

    /**
     * 根据id更新展厅管理员
     *
     * @param showroomAdminUpdateDTO
     */
    @Override
    @Transactional
    public void updateById(ShowroomAdminUpdateDTO showroomAdminUpdateDTO) {

        ShowroomAdmin showroomAdmin = new ShowroomAdmin();
        BeanUtils.copyProperties(showroomAdminUpdateDTO, showroomAdmin);

        Showroom showroom = showroomMapper.getShowroomById(showroomAdmin.getShowroomId());
        if (Objects.isNull(showroom)) throw new RuntimeException("展厅不存在");

//      showroomAdmin.setPassword(DigestUtils.md5DigestAsHex(showroomAdminDTO.getPassword().getBytes()));
        showroomAdmin.setPassword(passwordEncoder.encode(showroomAdminUpdateDTO.getPassword()));
        showroomAdminMapper.update(showroomAdmin);
        redisTemplate.opsForValue().getOperations().delete(RedisConstant.LOGIN_SHOWROOM_ADMIN + showroomAdmin.getId().toString());

        UserRole userRole = UserRole.builder()
                .role(RoleConstant.SHOWROOM_ADMIN)
                .roleId(showroomAdmin.getId())
                .phone(showroomAdmin.getPhone())
                .username(showroomAdmin.getUsername())
                .build();
        userRoleMapper.update(userRole);
    }

    /**
     * 查询所有展厅管理员
     *
     * @return
     */
    @Override
    public List<ShowroomAdminQueryVO> listAll() {
        return showroomAdminMapper.listAll();
    }

    /**
     * 根据id删除展厅管理员
     *
     * @param id
     */
    @Override
    public void deleteById(Long id) {
        showroomAdminMapper.deleteById(id);
        userRoleMapper.delete(UserRole.builder().roleId(id).role(RoleConstant.SHOWROOM_ADMIN).build());
        redisTemplate.opsForValue().getOperations().delete(RedisConstant.LOGIN_SHOWROOM_ADMIN + id.toString());
    }

    /**
     * 根据id查询展厅管理员
     * @param id
     * @return
     */
    @Override
    public ShowroomAdmin getShowroomAdminById(Integer id) {
        return showroomAdminMapper.selectById(id);
    }

    /**
     * 根据上下文更新展厅管理员
     *
     * @param showroomAdminUpdateDTO
     */
    @Override
    @Transactional
    public void updateByContext(ShowroomAdminUpdateDTO showroomAdminUpdateDTO) {

        Long id = null;
        try {
            id = SecurityContext.getCurrentLoginUser().getShowroomAdmin().getId();
        } catch (Exception e) {
            throw new RuntimeException("用户未登录");
        }

        ShowroomAdmin showroomAdmin = new ShowroomAdmin();
        BeanUtils.copyProperties(showroomAdminUpdateDTO, showroomAdmin);
        showroomAdmin.setId(id);

        Showroom showroom = showroomMapper.getShowroomById(showroomAdmin.getShowroomId());
        if (Objects.isNull(showroom)) throw new RuntimeException("展厅不存在");

//      showroomAdmin.setPassword(DigestUtils.md5DigestAsHex(showroomAdminDTO.getPassword().getBytes()));
        showroomAdmin.setPassword(passwordEncoder.encode(showroomAdminUpdateDTO.getPassword()));
        showroomAdminMapper.update(showroomAdmin);
        redisTemplate.opsForValue().getOperations().delete(RedisConstant.LOGIN_SHOWROOM_ADMIN + showroomAdmin.getId().toString());

        UserRole userRole = UserRole.builder()
                .role(RoleConstant.SHOWROOM_ADMIN)
                .roleId(showroomAdmin.getId())
                .phone(showroomAdmin.getPhone())
                .username(showroomAdmin.getUsername())
                .build();
        userRoleMapper.update(userRole);
    }

    /**
     * 分页查询展厅管理员
     *
     * @param showroomAdminPageQueryDTO
     * @return
     */
    @Override
    public PageResult pageQuery(ShowroomAdminPageQueryDTO showroomAdminPageQueryDTO) {
        PageHelper.startPage(showroomAdminPageQueryDTO.getPage(), showroomAdminPageQueryDTO.getPageSize());

        Page<ShowroomAdminQueryVO> page = showroomAdminMapper.pageQuery(showroomAdminPageQueryDTO);
        return new PageResult(page.getTotal(), page.getResult());

    }

    /**
     * 更新展厅管理员状态
     *
     * @param id
     * @param status
     */
    @Override
    public void updateStatus(Long id, Integer status) {
        showroomAdminMapper.updateStatus(id, status);
        redisTemplate.opsForValue().getOperations().delete(RedisConstant.LOGIN_SHOWROOM_ADMIN + id.toString());
    }

    /**
     * 退出登陆
     *
     * @return
     */
    @Override
    public Result logout() {
        UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        Long id = loginUser.getShowroomAdmin().getId();
        //在Redis中删除用户信息
        redisTemplate.opsForValue().getOperations().delete(RedisConstant.LOGIN_SHOWROOM_ADMIN + id);
        return Result.success();
    }
}
